package top.dimples.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.dimples.common.JWTUser;
import top.dimples.common.LuckyStatus;
import top.dimples.common.NoticeStatus;
import top.dimples.common.WinStatus;
import top.dimples.mapper.LuckyDrawMapper;
import top.dimples.model.LuckyDraw;
import top.dimples.model.LuckyWin;
import top.dimples.model.Notice;
import top.dimples.model.Prize;
import top.dimples.service.*;
import top.dimples.utils.BigWheelDrawUtil;
import top.dimples.vo.common.PageResult;
import top.dimples.vo.common.PageVO;
import top.dimples.vo.lucky.LuckyCountVO;
import top.dimples.vo.lucky.LuckyDrawVO;
import top.dimples.vo.lucky.PrizeVO;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Dimples_Yj
 * @package top.dimples.service.impl
 * @date 2021/12/18
 */
@Transactional(rollbackFor = RuntimeException.class)
@Service
public class LuckyDrawServiceImpl extends ServiceImpl<LuckyDrawMapper, LuckyDraw> implements LuckyDrawService {

    @Autowired
    private LuckyDrawService luckyDrawService;

    @Autowired
    private PrizeService prizeService;

    @Autowired
    private LuckyWinService luckyWinService;

    @Autowired
    private EmailManagerService emailManagerService;

    @Autowired
    private UserProfileService userProfileService;

    @Autowired
    private NoticeService noticeService;


    @Override
    public String addLuckyDraw(JWTUser jwtUser, LuckyDrawVO luckyDrawVO) {
        // 1、创建抽奖活动对象
        LuckyDraw luckyDraw = LuckyDraw.builder()
                .startTime(luckyDrawVO.getStartTime())
                .endTime(luckyDrawVO.getEndTime())
                .userId(jwtUser.getId())
                .title(luckyDrawVO.getTitle())
                .status(LuckyStatus.UNDER_REVIEW.getCode())
                .count(luckyDrawVO.getCount())
                .build();
        boolean save = luckyDrawService.save(luckyDraw);
        if (save) {
            List<Prize> prizes = new ArrayList<>();
            // 2、批量创建抽奖奖品对象
            luckyDrawVO.getPrizes().forEach(prizeVO -> {
                prizes.add(Prize.builder()
                        .luckyId(luckyDraw.getId())
                        .number(prizeVO.getNumber())
                        .probability(prizeVO.getProbability())
                        .prizeName(prizeVO.getPrizeName())
                        .text(prizeVO.getText())
                        .imgUrl(prizeVO.getImgUrl())
                        .build());
            });
            return prizeService.saveBatch(prizes) ? luckyDraw.getId() : null;
        }
        return null;
    }

    @Override
    public LuckyDrawVO getLuckDrawInfo(String id) {
        // 1、查出正在进行的抽奖活动
        LuckyDraw luckyDraw = luckyDrawService.getOne(new LambdaQueryWrapper<LuckyDraw>().eq(LuckyDraw::getId, id).eq(LuckyDraw::getStatus, LuckyStatus.UNDER_WAY.getCode()));
        // 2、查出活动的奖品
        if (ObjectUtil.isNotEmpty(luckyDraw)) {
            List<Prize> prizes = prizeService.list(new LambdaQueryWrapper<Prize>().eq(Prize::getLuckyId, id));
            List<PrizeVO> prizeVOList = prizes.stream().map(prize -> Convert.convert(PrizeVO.class, prize)).collect(Collectors.toList());
            LuckyDrawVO luckyDrawVO = Convert.convert(LuckyDrawVO.class, luckyDraw);
            luckyDrawVO.setPrizes(prizeVOList);
            return luckyDrawVO;
        }
        return null;
    }

    /**
     * 获取抽奖结果
     *
     * @param jwtUser jwt 解析的用户
     * @param id      活动的 id
     * @return 中奖的索引
     */
    @Override
    public Integer lotteryIndex(JWTUser jwtUser, String id) {
        LuckyDraw luckyDraw = luckyDrawService.getOne(new LambdaQueryWrapper<LuckyDraw>().eq(LuckyDraw::getId, id).eq(LuckyDraw::getStatus, LuckyStatus.UNDER_WAY.getCode()));
        long count = luckyWinService.count(new LambdaQueryWrapper<LuckyWin>().eq(LuckyWin::getLuckyId, id).eq(LuckyWin::getUserId, jwtUser.getId()));
        if (ObjectUtil.isNotEmpty(luckyDraw)) {
            if (count >= luckyDraw.getCount()) {
                return -2;
            }

            if (ObjectUtil.isNotEmpty(luckyDraw)) {
                List<Prize> prizes = prizeService.list(new LambdaQueryWrapper<Prize>().eq(Prize::getLuckyId, id));
                int index = BigWheelDrawUtil.lottery(prizes);
                Prize prize = prizes.get(index);
                LuckyWin luckyWin = LuckyWin.builder()
                        .userId(jwtUser.getId())
                        .luckyId(luckyDraw.getId())
                        .prizeId(prize.getId())
                        .status(WinStatus.LOSE.getCode())
                        .build();
                if (prize.getNumber() > 0) {
                    // 保存中奖记录
                    luckyWin.setStatus(WinStatus.WIN.getCode());
                    luckyWinService.save(luckyWin);

                    if (!StrUtil.containsAny(prize.getPrizeName(), '谢', '参', '与')) {

                        // 发送中奖邮件
                        emailManagerService.sendWinEmail(userProfileService.getById(jwtUser.getId()), prize);

                        // 添加中奖消息通知
                        noticeService.save(Notice.builder()
                                .message(StrUtil.format("恭喜您获得{}，奖品为{}一份", prize.getText(), prize.getPrizeName()))
                                .userId(jwtUser.getId())
                                .status(NoticeStatus.UNREAD.getCode())
                                .build());
                    }

                    // 奖品数量减少 1
                    prize.setNumber(prize.getNumber() - 1);
                    prizeService.updateById(prize);
                    Integer integer = prizes.stream().map(Prize::getNumber).reduce(Integer::sum).orElse(0);
                    // 如果所有的奖品都抽完了，结束该次活动
                    if (integer <= 0) {
                        this.update(new LambdaUpdateWrapper<LuckyDraw>()
                                .eq(LuckyDraw::getId, id)
                                .set(LuckyDraw::getStatus, LuckyStatus.COMPLETE.getCode()));

                        // 查出活动，通知活动创建者活动结束
                        LuckyDraw draw = this.getById(id);
                        noticeService.save(Notice.builder()
                                .message(StrUtil.format("您好，您创建的抽奖活动,结束啦!活动开始时间：{}，结束时间：{}", draw.getStartTime(), draw.getEndTime()))
                                .userId(draw.getUserId())
                                .status(NoticeStatus.UNREAD.getCode())
                                .build());
                    }

                    return index;
                }
                luckyWinService.save(luckyWin);
                return -1;
            }
        }
        return -1;
    }

    /**
     * 获取抽奖统计数据
     *
     * @param jwtUser jwt用户
     * @return 统计结果
     */
    @Override
    public LuckyCountVO getLuckyCount(JWTUser jwtUser) {
        long records = luckyWinService.count(new LambdaQueryWrapper<LuckyWin>().eq(LuckyWin::getUserId, jwtUser.getId()));
        long currents = luckyDrawService.count(new LambdaQueryWrapper<LuckyDraw>().eq(LuckyDraw::getUserId, jwtUser.getId()));
        long notices = noticeService.count(new LambdaQueryWrapper<Notice>().eq(Notice::getStatus, NoticeStatus.UNREAD.getCode()).eq(Notice::getUserId, jwtUser.getId()));
        long joins = luckyWinService.count(new QueryWrapper<LuckyWin>().select("DISTINCT lucky_id").eq(LuckyWin.COL_USER_ID, jwtUser.getId()));
        List<LuckyWin> list = luckyWinService.list(new LambdaQueryWrapper<LuckyWin>().eq(LuckyWin::getUserId, jwtUser.getId()).eq(LuckyWin::getStatus, WinStatus.WIN.getCode()));
        long wins = list.stream().filter(luckyWin -> !StrUtil.containsAny(prizeService.getById(luckyWin.getPrizeId()).getText().trim(), "谢谢参与")).count();
        return LuckyCountVO.builder()
                .currents(currents)
                .joins(joins)
                .notices(notices)
                .records(records)
                .wins(wins)
                .build();
    }

    /**
     * 获取当前用户发布的抽奖活动
     *
     * @param userId 用户的id
     * @return
     */
    @Override
    public PageResult<LuckyDraw> getUserLuckyDraw(String userId, PageVO pageVO) {
        Page<LuckyDraw> page = this.page(
                new Page<>(pageVO.getPageNum(), pageVO.getPageSize()),
                new LambdaQueryWrapper<LuckyDraw>()
                        .eq(LuckyDraw::getUserId, userId)
                        .orderByDesc(LuckyDraw::getCreateTime)
        );
        return PageResult.startPage(page);
    }
}
